/*
 * Copyright (c) 2012, 2021, daojian.co and/or its affiliates. All rights reserved.
 *
 */

package co.bugu.code.analysis.application.service;

import co.bugu.code.analysis.application.converter.BranchConverter;
import co.bugu.code.analysis.application.converter.CommitConverter;
import co.bugu.code.analysis.application.converter.EntityConverter;
import co.bugu.code.analysis.application.converter.ProjectConverter;
import co.bugu.code.analysis.infra.entity.Commit;
import co.bugu.code.analysis.infra.repo.*;
import co.bugu.framework.common.exception.CustomException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.gitlab4j.api.GitLabApi;
import org.gitlab4j.api.GitLabApiException;
import org.gitlab4j.api.models.Branch;
import org.gitlab4j.api.models.Diff;
import org.gitlab4j.api.models.Project;
import org.gitlab4j.api.models.User;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;


/**
 * 业务编排类
 *
 * @author happy-coder
 * @version 1.0.0
 * @createdAt 2022-06-11 11:21:37
 * @updatedAt 2022-06-11 11:21:37
 */
@Service
@Slf4j
public class ProjectService {

    @Autowired
    GitLabApi gitLabApi;

    @Autowired
    ProjectRepo projectRepo;


    @Autowired
    BranchRepo branchRepo;
    @Autowired
    CommitRepo commitRepo;
    @Autowired
    DiffRepo diffRepo;
    @Autowired
    UserRepo userRepo;

    @Autowired
    BranchService branchService;
    @Autowired
    CommitService commitService;
    @Autowired
    DiffService diffService;
    @Autowired
    UserService userService;


    /**
     * 获取项目
     * <p>
     * 只处理7天内有更新的项目
     *
     * @param
     * @return
     * @author alei
     * @date 2025/5/30 15:00
     */
    public void fetchDeltaProject() {
        int page = 1;
        int pageSize = 100;

        try {
            List<Project> projects = null;

            do {
                projects = gitLabApi.getProjectApi().getProjects(page, pageSize);
                if (CollectionUtils.isNotEmpty(projects)) {
                    projects.stream().forEach(project -> {

                        Date lastActivityAt = project.getLastActivityAt();
//                        处理七天以内的新增项目
                        if (lastActivityAt.getTime() > System.currentTimeMillis() - 7 * 24 * 60 * 60 * 1000) {
                            co.bugu.code.analysis.infra.entity.Project projectInDB = projectRepo.findById(project.getId());
                            if (null == projectInDB) {
                                projectInDB = new co.bugu.code.analysis.infra.entity.Project();
                                EntityConverter.gitlabToApp(project, projectInDB);
                                projectInDB.setProjectId(project.getId());
                                projectRepo.insert(projectInDB);
                            } else {
                                if (projectInDB.getLastActivityAt() != null && !projectInDB.getLastActivityAt().equals(project.getLastActivityAt())) {
                                    EntityConverter.gitlabToApp(project, projectInDB);
                                    projectRepo.updateById(projectInDB);
                                }
                            }
                        }
                        log.info("project： {}", project.getNameWithNamespace());
                    });
                } else {
                    break;
                }
                page++;
            } while (projects.size() == pageSize);
        } catch (Exception e) {
            log.error("获取项目失败", e);
        }
    }


    /**
     * 获取项目分支信息
     * 如果不指定，则获取三年内有更新的分支
     *
     * @param
     * @return
     * @author alei
     * @date 2025/6/3 14:32
     */
    public void fetchDeltaBranch(Long projectId, Date begin, Date end) {
        try {
            List<org.gitlab4j.api.models.Branch> branches = gitLabApi.getRepositoryApi().getBranches(projectId);
            if (CollectionUtils.isEmpty(branches)) {
                return;
            }
            if (null == begin) {
                begin = new Date(System.currentTimeMillis() - 1000 * 60 * 60 * 24 * 365 * 3L);
            }
            if (null == end) {
                end = new Date();
            }
            if (begin.after(end)) {
                throw new CustomException(String.format("起止时间不合法，%s - %s", begin, end));
            }
            for (org.gitlab4j.api.models.Branch branch : branches) {
                Date committedDate = branch.getCommit().getCommittedDate();
                if (committedDate.before(begin) || committedDate.after(end)) {
                    log.info("");
                    continue;
                }
                co.bugu.code.analysis.infra.entity.Branch branchInDB = branchService.findByProjectAndName(projectId, branch.getName());
                if (null == branchInDB) {
                    co.bugu.code.analysis.infra.entity.Branch item = BranchConverter.convert(projectId, branch);
                    branchRepo.insert(item);
                } else {
                    co.bugu.code.analysis.infra.entity.Branch item = BranchConverter.convert(projectId, branch);
                    item.setId(branchInDB.getId());
                    branchRepo.updateById(item);
                }

            }
        } catch (GitLabApiException e) {
            log.error("获取分支失败", e);
        }
    }


    /**
     * 获取指定项目的所有分支信息
     *
     * @param projectId GitLab 项目ID
     * @return 分支列表
     * @throws GitLabApiException GitLab API 异常
     */
    public List<Branch> getAllBranchesByProject(Integer projectId) throws GitLabApiException {
        List<Branch> branches = gitLabApi.getRepositoryApi().getBranches(projectId);
        return branches;
    }

    /**
     * 获取指定项目的 所有分支的提交记录，并附带分支名称
     *
     * @param projectId 项目ID
     * @return List<CommitWithBranch>
     * @throws Exception
     */
    public List<Commit> fetchDeltaCommitsWithBranchInfo(Long projectId, Long branchId, String branchName, Date begin, Date end) {
        List<Commit> result = new ArrayList<>();

        try {
            // 获取该分支的所有提交
            List<org.gitlab4j.api.models.Commit> commits = gitLabApi.getCommitsApi().getCommits(projectId, branchName, begin, end, null, false, true, true);

            // 组装数据：commit + branchName
            for (org.gitlab4j.api.models.Commit commit : commits) {
                Commit res = CommitConverter.convert(projectId, branchId, branchName, commit);
                result.add(res);
            }
            commitRepo.batchAddFreeMode(result);
        } catch (Exception e) {
            log.error("获取分支 {} 的提交失败", branchName, e);
        }
        return result;
    }

    /**
     * 获取指定 commit 的所有文件变更统计（适用于 gitlab4j-api 5.x）
     *
     * @param projectId 项目ID
     * @param commit    提交信息
     * @return 每个文件的变更统计列表
     */
    public List<co.bugu.code.analysis.infra.entity.Diff> getDiffByCommit(Long projectId, Commit commit) {
        try {
            // 获取 diff 列表（每个文件的 diff）
            List<Diff> diffs = gitLabApi.getCommitsApi().getDiff(projectId, commit.getShortId());

            List<co.bugu.code.analysis.infra.entity.Diff> list = new ArrayList<>();
            for (Diff diff : diffs) {
                int additions = 0;
                int deletions = 0;

                // 解析 changes 字段
                String changes = diff.getDiff();
                if (changes != null && !changes.isEmpty()) {
                    String[] lines = changes.split("\n");
                    for (String line : lines) {
                        if (line.startsWith("+") && !line.startsWith("+++")) {
                            additions++;
                        } else if (line.startsWith("-") && !line.startsWith("---")) {
                            deletions++;
                        }
                    }
                }

                // 获取文件路径（优先新路径）
                String filePath = diff.getNewPath() != null ? diff.getNewPath() : diff.getOldPath();

                co.bugu.code.analysis.infra.entity.Diff diffInfo = new co.bugu.code.analysis.infra.entity.Diff();
                BeanUtils.copyProperties(diff, diffInfo);
                diffInfo.setCommittedDate(commit.getCommittedDate());
                diffInfo.setAdditions(additions);
                diffInfo.setDeletions(deletions);
                diffInfo.setCommitId(commit.getCommitId());
                diffInfo.setBranchName(commit.getBranchName());
                if (diff.getDiff().length() > 4000) {
                    diffInfo.setDiff("length:" + diff.getDiff().length() + " content:" + diff.getDiff().substring(0, 4000));
                }

                list.add(diffInfo);
            }
            diffRepo.batchAddFreeMode(list);
            return list;
        } catch (Exception e) {
            log.error("获取提交 {} 的文件变更统计失败", commit.getShortId(), e);
        }
        return null;
    }


    public void fetchDeltaUser(Date begin, Date end) {
        try {
            List<User> users = gitLabApi.getUserApi().getUsers();
            if (CollectionUtils.isNotEmpty(users)) {
                for (User user : users) {
                    Date lastActivityOn = user.getLastActivityOn();
                    if (null == lastActivityOn || lastActivityOn.before(begin) || lastActivityOn.after(end)) {
                        continue;
                    }
                    if (null == userService.findByUserId(user.getId())) {
                        co.bugu.code.analysis.infra.entity.User item = new co.bugu.code.analysis.infra.entity.User();
                        BeanUtils.copyProperties(user, item);
                        item.setUserId(user.getId());
                        userRepo.insert(item);
                    } else {
                        co.bugu.code.analysis.infra.entity.User infraUser = userService.findByUserId(user.getId());
                        if (!infraUser.getLastActivityOn().equals(user.getLastActivityOn())) {
                            infraUser.setLastActivityOn(user.getLastActivityOn());
                            userRepo.updateById(infraUser);
                        }

                    }
                }
            }
        } catch (Exception e) {
            log.error("获取用户失败", e);
        }

    }


    public List<co.bugu.code.analysis.infra.entity.Project> fetchAllProject() {
        List<co.bugu.code.analysis.infra.entity.Project> res = new ArrayList<>();
        try {
            int page = 1;
            int pageSize = 100;
            List<Project> projects = new ArrayList<>();
            do {
                projects = gitLabApi.getProjectApi().getProjects(page, pageSize);
                if (CollectionUtils.isNotEmpty(projects)) {
                    List<co.bugu.code.analysis.infra.entity.Project> list = projects.stream().map(project -> {
                        co.bugu.code.analysis.infra.entity.Project item = ProjectConverter.convert(project);
                        return item;
                    }).collect(Collectors.toList());

                    /*分页批量插入list， 每页100条数据*/
                    for (int i = 0; i < list.size(); i += 10) {
                        List<co.bugu.code.analysis.infra.entity.Project> subList = list.subList(i, Math.min(i + 10, list.size()));
                        try {
                            projectRepo.batchAddFreeMode(subList);
                        } catch (Exception e) {
                            log.warn("批量插入失败，降级为单条插入", e);
                            subList.forEach(item -> projectRepo.insert(item));
                        }


                    }
                    res.addAll(list);
                }
                page++;
            } while (projects.size() == pageSize);

        } catch (Exception e) {
            log.error("获取项目失败", e);
        }
        return res;
    }


    public List<co.bugu.code.analysis.infra.entity.Branch> fetchAllBranch(Long projectId) {
        try {
            List<Branch> branches = gitLabApi.getRepositoryApi().getBranches(projectId);
            if (CollectionUtils.isNotEmpty(branches)) {
                List<co.bugu.code.analysis.infra.entity.Branch> list = branches.stream().map(branch -> {
                    co.bugu.code.analysis.infra.entity.Branch item = BranchConverter.convert(projectId, branch);
                    return item;
                }).collect(Collectors.toList());

                /*分页批量插入list， 每页100条数据*/
                for (int i = 0; i < list.size(); i += 100) {
                    List<co.bugu.code.analysis.infra.entity.Branch> subList = list.subList(i, Math.min(i + 100, list.size()));
                    branchRepo.batchAddFreeMode(subList);
                }
                return list;
            }

        } catch (Exception e) {
            log.error("获取项目{}分支失败", projectId, e);
        }
        return new ArrayList<>();
    }


    public List<Commit> fetchAllCommit(Long projectId, Long branchId, String branchName) {
        try {
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            // 获取该分支的所有提交
            List<org.gitlab4j.api.models.Commit> commits = gitLabApi.getCommitsApi().getCommits(projectId, branchName, format.parse("2024-01-01 00:00:00"), new Date(), null, false, true, true);

            if (CollectionUtils.isNotEmpty(commits)) {
                List<co.bugu.code.analysis.infra.entity.Commit> list = commits.stream().map(commit -> {
                    co.bugu.code.analysis.infra.entity.Commit item = CommitConverter.convert(projectId, branchId, branchName, commit);
                    return item;
                }).collect(Collectors.toList());
                /*分页批量插入list， 每页100条数据*/
                for (int i = 0; i < list.size(); i += 100) {
                    List<co.bugu.code.analysis.infra.entity.Commit> subList = list.subList(i, Math.min(i + 100, list.size()));
                    commitRepo.batchAddFreeMode(subList);
                }
                return list;
            }
        } catch (Exception e) {
            log.error("获取提交{}失败", projectId, e);
        }
        return new ArrayList<>();
    }


}
